
from .config import *
from .store import GetGlobalDB
from .obj import Lancer,Tag,Uuid
import json
import os
import uuid
from meta_service.utils import *
from .utils import *
import arxiv

def CheckEntryIdType(entry_id:str):
    if is_valid_uuid4(entry_id):
        return NORMALTYPEID
    if is_valid_aid(entry_id):
        return ARXIVTYPEID
    return UNKNOWNTYPEID

def get_seq(line:str):
    all = "".join([ ch.lower() for ch in line if ch.isalpha() ])
    return all

def GenNormalEntryId():
    MAX_RANGE_COUNT = 10
    entry_id = None
    for _ in range(MAX_RANGE_COUNT):
        entry_id = uuid.uuid4()
        if GetGlobalDB().HasEntryId(entry_id):
            entry_id = None
            continue
        return entry_id
    return None

def SearchEntryIdOnline(id:str):
    r = next(arxiv.Client().results(arxiv.Search(id_list=[str(id)])))
    entry_id_url = str(r.entry_id)
    entry_id = str(entry_id_url.split("/")[-1])
    if entry_id.lower().startswith(id.lower()):
        return entry_id, r
    return None,None

class AnyLancer:

    def __init__(self,entry_id:str=None) -> None:
        if entry_id is None:
            self.__set_all_none()
        else:
            if not self.__auto_load(entry_id):
                self.__set_all_none()
       
    def gen_normal_id(self):
        self.entry_id = GenNormalEntryId()
        if self.entry_id is None:
            raise Exception("GenNormalEntryId failed")
        return self.entry_id
    
    def __auto_load(self,entry_id):
        self.entry_id = entry_id
        self.idtype = CheckEntryIdType(self.entry_id)
        loadok = False
        try:
            loadok = self.__load_from_db(entry_id)
            if loadok:
                return True
        except Exception as e:
            loadok = False
        
        if self.__auto_search_online():
            return True
        return False

    def __auto_search_online(self):
        if self.idtype == ARXIVTYPEID:
            entry_id,r = SearchEntryIdOnline(self.entry_id)
            if r is None:
                print("search entry online failed")
                return False
            self.entry_id = entry_id
            self.title = r.title
            self.summary = r.summary
            self.comment = r.comment
            self.site_url = r.entry_id
            self.page_url = r.pdf_url
            self.authors = [ str(one.name) for one in r.authors ]
            self.categories = [ str(one) for one in r.categories ]
            self.primary_category = r.primary_category
            self.raw = dict(r._raw)
            if not self.__store_to_db():
                print("online result cannot store to db")
                return False
            return True
        return False
    
    def __set_all_none(self):
        self.entry_id = None
        self.idtype = None
        self.title = None
        self.summary = None
        self.comment = None
        self.site_url = None
        self.page_url = None
        self.raw:dict = None
        self.authors:list[str] = None
        self.categories:list[str] = None
        self.primary_category = None
    
    def __get_thash(self):
        return get_seq(format_title(self.title))
    
    def StoreToDB(self):
        return self.__store_to_db()

    def __store_to_db(self):
        if not GetGlobalDB().HasEntryId(self.entry_id):
            if not GetGlobalDB().AddEntryIdOnly(
                self.entry_id,
                tihash=self.__get_thash(),
                idtype=CheckEntryIdType(self.entry_id),
                refs=str(self.title),
            ):
                return False
        # 添加条目
        item = Lancer(
            EntryId=self.entry_id,
            Title=self.title,
            Summary=self.summary,
            Comment=self.comment,
            SiteUrl=self.site_url,
            PageUrl=self.page_url,
            RawJson=json.dumps(self.raw),
            Authors=json.dumps(self.authors),
            Categories=json.dumps(self.categories),
            PrimaryCategory=self.primary_category
        )
        return GetGlobalDB().AddEntryItem(item)

    def __load_from_db(self,entry_id):
        item = GetGlobalDB().GetEntryItem(entry_id)
        if item is None:
            print(f"not found")
            return False
        self.entry_id = item.EntryId
        self.title = item.Title
        self.summary = item.Summary
        self.comment = item.Comment
        self.site_url = item.SiteUrl
        self.page_url = item.PageUrl
        self.raw:dict = json.loads(item.RawJson)
        self.authors:list[str] = json.loads(item.Authors)
        self.categories:list[str] = json.loads(item.Categories)
        self.primary_category = item.PrimaryCategory
        self.idtype = CheckEntryIdType(self.entry_id)
        return True
    
    def get_id_type(self):
        if self.idtype is None:
            self.idtype = CheckEntryIdType(self.entry_id)
        return self.idtype

    def download_to_dir(self,save_dir:str):
        filename = f"{self.entry_id}.pdf"
        try:
            download_pdf(self.page_url,save_dir,filename)
            sizef = get_file_size(os.path.join(save_dir,filename))
            return sizef > 0
        except Exception as e:
            print(f"error in download to dir: {str(e)}")
        return False
     
    def download_to_file(self,save_file_path:str):
        try:
            save_file_path = os.path.abspath(save_file_path)
            filename = os.path.basename(save_file_path)
            save_dir = os.path.dirname(save_file_path)
            download_pdf(self.page_url,save_dir,filename)
            sizef = get_file_size(os.path.join(save_dir,filename))
            return sizef > 0
        except Exception as e:
            print(f"error in download to dir: {str(e)}")
        return False

    def get_pdf_url(self):
        return str(self.page_url)
    
    def get_entry_id(self) -> str:
        return str(self.entry_id)
    
    def get_comment(self) -> str:
        return str(self.comment)

    def get_author(self) -> list[str]:
        return [ str(one) for one in self.authors ]
    
    def get_summary(self) -> str:
        return str(self.summary)
    
    def get_title(self) -> str:
        return str(self.title)
    
    def get_title_formated(self) -> str:
        title = format_title(self.title)
        return title if len(title) > 0 else str(self.title)

    def get_site_url(self):
        return str(self.site_url)
    
    @staticmethod
    def ExistEntryId(entry_id) -> bool:
        return GetGlobalDB().HasEntryId(entry_id)

def ExecuteSQL(sql:str):
    return GetGlobalDB().Execute(sql)

def GetAllEntryIds() -> list[str]:
    return GetGlobalDB().GetAllEntryId()


